//
//  StrokeViewContainer.m
//  StrokeDemo
//
//  Created by wankang on 2/26/15.
//  Copyright (c) 2015 wankang. All rights reserved.
//

#import "StrokeViewContainer.h"
#import "StrokeRecord.h"

#import "DataProcessing.h"

#ifndef _countof
#define _countof(A) (sizeof(A)/sizeof(A[0]))
#endif  // _countof

//////////////////////////////////////////////////////////////////////

typedef const char *LPCSTR;

static LPCSTR STROKE_MAP[] = {
    "横", "h",
    "竖", "s",
    "撇", "p",
    "捺", "n",
    "提", "t",
    "钩", "g",
    "点", "d",
    "折", "z",
    "斜", "x",
    "弯", "w",
    "卧", "o",
    "左", "u",
};

LPCSTR getStrokeMapName(LPCSTR sChn)
{
    if (!sChn || !(*sChn & 0x80))
        return NULL;
    int nMapCount = _countof(STROKE_MAP);
    for (int i=0; i+1<nMapCount; i+=2) {
        if (strcmp(STROKE_MAP[i], sChn) == 0)
            return STROKE_MAP[i+1];
    }
    return NULL;
}

//////////////////////////////////////////////////////////////////////

@implementation StrokeViewContainer
@synthesize viewStroke = _viewStroke;
@synthesize soundPath = _soundPath;

- (id)init
{
    if (self = [super init]) {
        _viewStroke = nil;
        _soundPath = nil;
        [self initData];
    }
    return self;
}

- (id)initWithStrokeView:(UIStrokeView *)view
{
    if (self = [super init]) {
        _viewStroke = view;
        _soundPath = nil;
        [self initData];
    }
    return self;
}

- (void)initData
{
    mLoader = nil;
    mPlayer = nil;
    mNotify = nil;
    //mChn2Py = nil;
    //mPy2Wave = nil;
    mTempWave = nil;
}

- (void)dealloc
{
    [self close];
}

- (void)close
{
    if (_viewStroke != nil) {
        [_viewStroke stopFilling];
        _viewStroke.delegate = nil;
        _viewStroke = nil;
    }
    _soundPath = nil;
    if (mLoader != nil) {
        [mLoader close];
        mLoader = nil;
    }
/*    if (mChn2Py != nil) {
        [mChn2Py close];
        mChn2Py = nil;
    }
    if (mPy2Wave != nil) {
        [mPy2Wave close];
        mPy2Wave = nil;
    }//*/
    mPlayer = nil;
    mNotify = nil;
    if (mTempWave != nil) {
        NSError *e;
        [[NSFileManager defaultManager] removeItemAtPath:mTempWave error:&e];
        mTempWave = nil;
    }
}

- (BOOL)initWithDBPath:(NSString *)sDBPath guidePath:(NSString *)sGuidePath
{
    if (_viewStroke == nil || sDBPath == nil || sDBPath.length == 0)
        return NO;
    _viewStroke.delegate = self;
    // to load stroke.db
    mLoader = [[StrokeRecordLoader alloc] initWithPath:sDBPath];
    if (mLoader == nil) {
        NSLog(@"file stroke.db is missing:%@", sDBPath);
        return NO;
    }
    // to enable to call fill.db
    if (sGuidePath != nil && sGuidePath.length > 0)
        mLoader.guidePath = sGuidePath;
    return YES;
}

- (void)playSound:(NSString *)sChn forStroke:(BOOL)fStroke withNotify:(id<PlaySoundEndNotify>)notify
{
    BOOL fRemoveFile = NO;
    NSString *sFile = nil;
    if (fStroke) {
        NSString *sName;
        NSString *sFileName = [StrokeViewContainer getStrokeWaveName:sChn];
        if (sFileName!=nil && sFileName.length>0) {
            if (_soundPath!=nil && _soundPath.length>0)
                sName = [NSString stringWithFormat:@"%@/%@",_soundPath,sFileName];
            else
                sName = sFileName;
            //telen 更改到网络下载位置
            //sFile = [[NSBundle mainBundle] pathForResource:sName ofType:@"wav"];
            sFile = [[DataProcessing shareSingle].supportFilesDirector stringByAppendingPathComponent:sName];
            sFile = [sFile stringByAppendingPathExtension:@"wav"];
        }
    } else {
        sFile = [self getWavePathFromChnCode:sChn];
        if (sFile!=nil && sFile.length>0)
            fRemoveFile = YES;
    }
    if (sFile==nil || sFile.length==0 || ![[NSFileManager defaultManager] fileExistsAtPath:sFile]) {
        NSLog(@"no sound for:%@", sChn);
        sleep(1);
        if (notify != nil) {
            [notify onPlayEnd];
        }
    } else {
        NSError *e;
        NSURL *url = [[NSURL alloc] initFileURLWithPath:sFile];
        mPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&e];
        [mPlayer setDelegate:self];
        if (fRemoveFile)
            mTempWave = sFile;
        mNotify = notify;
        [mPlayer play];
    }
}

- (NSArray *)getStrokeForChn:(NSString *)sChn width:(NSInteger)maxWidth height:(NSInteger)maxHeight
{
    // to check arguments
    if (mLoader == nil || sChn == nil || sChn.length != 1)
        return nil;
    if (maxWidth < 16 || maxHeight < 16 ||
        maxWidth >= 65536 || maxHeight >= 65536) {
        NSLog(@"size is too small/large:%d, %d", (int)maxWidth, (int)maxHeight);
        return nil;
    }
    // to load record from stroke.db, may fail
    NSArray *sResult = [mLoader loadRecordFromCode:sChn withContour:YES withMidline:NO];
    if (sResult == nil || sResult.count == 0 || (maxWidth == 267 && maxHeight == 267))
        return sResult;
    // to create scaled result
    float fX = (maxWidth / 267.0f);
    float fY = (maxHeight / 267.0f);
    int nSize = (int)sResult.count;
    NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:nSize];
    for (int i=0; i<nSize; i++) {
        StrokeRecord *rOld = [sResult objectAtIndex:i];
        StrokeRecord *rNew = [rOld createRecordWithXScale:fX andYScale:fY];
        [arr addObject:rNew];
    }
    return arr;
}

- (NSArray *)getGuideForChn:(NSString *)sChn withContourIndex:(NSInteger)index width:(NSInteger)maxWidth height:(NSInteger)maxHeight
{
    if (mLoader == nil || sChn == nil || sChn.length != 1 || index < 0)
        return nil;
    if (maxWidth < 16 || maxHeight < 16 ||
        maxWidth >= 65536 || maxHeight >= 65536) {
        NSLog(@"size is too small/large:%d, %d", (int)maxWidth, (int)maxHeight);
        return nil;
    }
    NSArray *sResult = [mLoader getChnGuide:sChn withStrokeIndex:index];
    if (sResult == nil || sResult.count == 0 || (maxWidth == 267 && maxHeight == 267))
        return sResult;
    return [StrokeRecord createScaledPoint:sResult withXScale:maxWidth/267.0f andYScale:maxHeight/267.0f];
}

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
    mPlayer = nil;
    if (mNotify != nil) {
        [mNotify onPlayEnd];
        mNotify = nil;
    }
    if (mTempWave != nil) {
        NSError *e;
        [[NSFileManager defaultManager] removeItemAtPath:mTempWave error:&e];
        mTempWave = nil;
    }
}

/////////////////////////////////////////////////////////////////////////////////

- (BOOL)initChn2Py
{
/*    if (mChn2Py == nil) {
        NSString *sName;
        if (_soundPath!=nil && _soundPath.length>0)
            sName = [NSString stringWithFormat:@"%@/zi2yin", _soundPath];
        else
            sName = @"zi2yin";
        NSString *sPath = [[NSBundle mainBundle] pathForResource:sName ofType:@"dat"];
        if (sPath == nil) {
            NSLog(@"no zi2yin.dat.");
            return NO;
        }
        mChn2Py = [[NSChn2Py alloc] initWithPath:sPath];
        if (mChn2Py == nil) {
            NSLog(@"fail to load:NSChn2Py");
            return NO;
        }
    }
    return YES;//*/
    return NO;
}

- (BOOL)initPy2Wave
{
/*    if (mPy2Wave == nil) {
        NSString *sName;
        if (_soundPath!=nil && _soundPath.length>0)
            sName = [NSString stringWithFormat:@"%@/wave", _soundPath];
        else
            sName = @"wave";
        NSString *sPath = [[NSBundle mainBundle] pathForResource:sName ofType:@"db"];
        if (sPath == nil) {
            NSLog(@"no wave.db.");
            return NO;
        }
        mPy2Wave = [[NSPy2Wave alloc] initWithPath:sPath];
        if (mPy2Wave == nil) {
            NSLog(@"fail to load:NSPy2Wave");
            return NO;
        }
    }
    return YES;//*/
    return NO;
}

+ (NSString *)createTempWave
{
    NSString *sPath = nil;
    NSString *sFolder = NSTemporaryDirectory();
    if (sFolder == nil) {
        NSLog(@"fail to get temporary directory.");
        return nil;
    }
    for(int i = 0; i >= 0; i++) {
        NSString *sFile = [sFolder stringByAppendingPathComponent:[NSString stringWithFormat:@"u%x.wav", i]];
        if (![[NSFileManager defaultManager] fileExistsAtPath:sFile]) {
            sPath = sFile;
            break;
        }
    }
    return sPath;
}

- (NSString *)getWavePathFromChnCode:(NSString *)sChnCode
{
/*    if (![self initChn2Py] || ![self initPy2Wave])
        return nil;
    NSString *sPy = [mChn2Py getChnPy:sChnCode];
    if (sPy == nil || sPy.length == 0) {
        NSLog(@"no pinyin for:%@", sChnCode);
        return nil;
    }
    // some Chn will get pinyin list being seperated by ' ', e.g. 才
    NSString *sPyList = [sPy stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    NSRange rangeSpace = [sPyList rangeOfString:@" "];
    NSString *sRead = sPyList;
    if (rangeSpace.length > 0) {
        sRead = [sPyList substringToIndex:rangeSpace.location];
    }
    NSString *sPath = [StrokeViewContainer createTempWave];
    if (sPath==nil || sPath.length==0 || ![mPy2Wave getWave:sPath fromPy:sRead]) {
        NSLog(@"fail to get wave for PinYin:%@", sRead);
        return nil;
    }
    return sPath;//*/
    return nil;
}

+ (NSString *)getStrokeWaveName:(NSString *)sChnName
{
    if (sChnName == nil || sChnName.length == 0)
        return nil;
    NSRange range;
    range.length = 1;
    char szBuf[20];
    int nOut = 0;
    int nCount = (int)sChnName.length;
    for (int i=0; i<nCount && nOut<10; i++) {
        range.location = i;
        NSString *sChn = [sChnName substringWithRange:range];
        LPCSTR szMap = getStrokeMapName(sChn.UTF8String);
        if (!szMap || !*szMap)
            return nil;
        szBuf[nOut++] = szMap[0];
    }
    szBuf[nOut] = '\0';
    return [NSString stringWithCString:szBuf encoding:NSASCIIStringEncoding];
}
@end
